﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PalSave
{
    public partial class RpgData : Form
    {
        internal DataHandle CurrentHandle;
        private byte[] RpgDataBytes;
        public RpgData(string rpg)
        {
            this.RpgFileName = rpg;
            this.CurrentHandle = new DataHandle(rpg);
            //this.RpgDataBytes = CurrentHandle.getRpgDataBytes();

            InitializeComponent();

            // Initialize Values
            this.LinghuBox.Text = CurrentHandle.LinghuValue.ToString();
            this.MoneyBox.Text = CurrentHandle.Money.ToString();
        }


        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            base.OnFormClosed(e);
            Application.Exit();
        }

        private void linghuLabel_Click(object sender, EventArgs e)
        {
            if (this.linghuLabel.Text.Equals("靈葫值"))
            {
                linghuLabel.Text += " : " + CurrentHandle.LinghuValue.ToString();
            }
        }

        private void MoneyLable_Click(object sender, EventArgs e)
        {
            if (this.moneyLable.Text.Equals("財產"))
            {
                moneyLable.Text += " : " + CurrentHandle.Money.ToString();
            }
        }

        private void buttonExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void LinghuModify_Click(object sender, EventArgs e)
        {
            try
            {
                Int16 tmpLinghuValue = Int16.Parse(LinghuBox.Text);
                if (tmpLinghuValue < 0 || tmpLinghuValue > (0x10000/2 -1))
                {
                    MessageBox.Show("數值範圍不正確");
                }
                else
                {
                    this.CurrentHandle.LinghuValue = tmpLinghuValue;
                    this.linghuLabel.Text =
                        "靈葫值 : " + this.CurrentHandle.LinghuValue.ToString();
                }
            }
            catch
            {
                MessageBox.Show("請輸入正確的數字格式");
            }
        }

        private void MoneyModify_Click(object sender, EventArgs e)
        {
            try
            {
                Int32 tmpMoney = Int32.Parse(MoneyBox.Text);
                if (tmpMoney < 0 || tmpMoney > (0x100000000/2 -1))
                {
                    MessageBox.Show("數值範圍不正確");
                }
                else
                {
                    this.CurrentHandle.Money = tmpMoney;
                    this.moneyLable.Text =
                        "財產 : " + this.CurrentHandle.Money.ToString();
                }
            }
            catch
            {
                MessageBox.Show("請輸入正確的數字格式");
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            this.CurrentHandle.Save();
        }

        private void labelLixiaoyaoCurrentXP_Click(object sender, EventArgs e)
        {
            labelLixiaoyaoCurrentXP.Text += " : " + CurrentHandle.Lixiaoyao.CurrentXP.ToString();
        }

        private void buttonModifyLixiaoyaoCurrentXP_Click(object sender, EventArgs e)
        {
            try
            {
                Int32 tmpXP = Int32.Parse(textBoxLixiaoyaoCurrentXP.Text);
                if (tmpXP < 0 || tmpXP > (0x100000000/2 -1))
                {
                    MessageBox.Show("數值範圍不正確");
                }
                else
                {
                    this.CurrentHandle.Lixiaoyao.CurrentXP = tmpXP;
                    this.labelLixiaoyaoCurrentXP.Text =
                        "現有經驗 : " + this.CurrentHandle.Lixiaoyao.CurrentXP.ToString();
                }
            }
            catch
            {
                MessageBox.Show("請輸入正確的數字格式");
            }
        }

        private void labelLixiaoyaoUpgradeXP_Click(object sender, EventArgs e)
        {
            labelLixiaoyaoUpgradeXP.Text += " : "+ CurrentHandle.Lixiaoyao.UpgradeXP.ToString();
        }

        private void buttonModifyLixiaoyaoUpgradeXP_Click(object sender, EventArgs e)
        {
            try
            {
                Int32 tmpXP = Int32.Parse(textBoxLixiaoyaoUpgradeXP.Text);
                if (tmpXP < 1 || tmpXP > (0x100000000 / 2 - 1))
                {
                    MessageBox.Show("數值範圍不正確");
                }
                else
                {
                    this.CurrentHandle.Lixiaoyao.UpgradeXP = tmpXP;
                    this.labelLixiaoyaoUpgradeXP.Text =
                        "升級經驗 : " + this.CurrentHandle.Lixiaoyao.UpgradeXP.ToString();
                }
            }
            catch
            {
                MessageBox.Show("請輸入正確的數字格式");
            }
        }

        private void labelLixiaoyaoHeadWear_Click(object sender, EventArgs e)
        {
            this.labelLixiaoyaoHeadWear.Text += this.CurrentHandle.Lixiaoyao.HeadWear.ToString();
        }

        private void labelLixiaoyaoOuterArmor_Click(object sender, EventArgs e)
        {
            this.labelLixiaoyaoOuterArmor.Text += this.CurrentHandle.Lixiaoyao.OuterArmor.ToString();
        }

        private void labelLixiaoyaoInnerArmor_Click(object sender, EventArgs e)
        {
            this.labelLixiaoyaoInnerArmor.Text +=this.CurrentHandle.Lixiaoyao.InnerArmor.ToString();
        }
    }
    internal class Character
    {
        private DataHandle dataHandle;

        private Int16 CharacterNo;

        private bool isInTeam;
        private int MemberNumber;
        private int XAxis;
        private int YAxis;
        private Int16[] Abilities;

        private Int32 currentXP;
        public Int32 CurrentXP
        {
            get
            {
                return currentXP;
            }
            set
            {
                currentXP = value;
            }
        }

        private Int32 upgradeXP;
        public Int32 UpgradeXP
        {
            get
            {
                return upgradeXP;
            }
            set
            {
                upgradeXP=value;
            }
        }

        private Int16 headWear;
        public Int16 HeadWear
        {
            get
            {
                return headWear;
            }
            set
            {
               headWear =value;
            }
        }

        private Int16 outerArmor;
        public Int16 OuterArmor
        {
            get
            {
                return outerArmor;
            }
            set
            {
                outerArmor=value;
            }
        }

        private Int16 innerArmor;
        public Int16 InnerArmor
        {
            get
            {
                return innerArmor;
            }
            set
            {
               innerArmor =value;
            }
        }

        private Int16 weapon;
        public Int16 Weapon
        {
            get
            {
                return weapon;
            }
            set
            {
                weapon=value;
            }
        }

        private Int16 footWear;
        public Int16 FootWear
        {
            get
            {
                return footWear;
            }
            set
            {
               footWear =value;
            }
        }

        private Int16 accessoryWear;
        public Int16 AccessoryWear
        {
            get
            {
                return accessoryWear;
            }
            set
            {
               accessoryWear =value;
            }
        }

        public Character(Int16 character_no, DataHandle dhl)
        {
            byte[] tmp = dhl.getRpgDataBytes();
            if (character_no >= 0 && character_no <= 5)
            {
                this.CharacterNo = (Int16)character_no;
            }
            else
            {
                throw new Exception("No such character");
            }


            this.Abilities = new Int16[32];

            //
            // Get Character's existing status and position
            //
            if ((Int16)tmp[DataHandle.MEMBER_POSITION_LOCATION] == this.CharacterNo)
            {
                this.isInTeam = true;
                this.MemberNumber = 0;
                this.XAxis = (int)tmp[DataHandle.MEMBER_POSITION_LOCATION +
                    DataHandle.EACH_MEMBER_VALUE_LENGTH];
                this.YAxis = (int)tmp[DataHandle.MEMBER_POSITION_LOCATION +
                    (2 * DataHandle.EACH_MEMBER_VALUE_LENGTH)];
            }
            else if ((Int16)tmp[DataHandle.POS2_LOCATION] == this.CharacterNo)
            {
                this.isInTeam = true;
                this.MemberNumber = 1;
                this.XAxis = (int)tmp[DataHandle.POS2_LOCATION +
                    DataHandle.EACH_MEMBER_VALUE_LENGTH];
                this.YAxis = (int)tmp[DataHandle.POS2_LOCATION +
                    (2 * DataHandle.EACH_MEMBER_VALUE_LENGTH)];
            }
            else if ((Int16)tmp[DataHandle.POS3_LOCATION] == this.CharacterNo)
            {
                this.isInTeam = true;
                this.MemberNumber = 2;
                this.XAxis = (int)tmp[DataHandle.POS3_LOCATION +
                    DataHandle.EACH_MEMBER_VALUE_LENGTH];
                this.YAxis = (int)tmp[DataHandle.POS3_LOCATION +
                    (2 * DataHandle.EACH_MEMBER_VALUE_LENGTH)];
            }
            else
            {
                this.isInTeam = false;
            }

            //
            //Get Character's XP data
            //
            this.currentXP = BitConverter.ToInt32(tmp,
                DataHandle.XP_LOCATION + (this.CharacterNo * DataHandle.EACH_CHARACTER_LENGTH));
            this.upgradeXP = BitConverter.ToInt32(tmp,
                DataHandle.XP_LOCATION +
                (this.CharacterNo * DataHandle.EACH_CHARACTER_LENGTH) + DataHandle.EACH_XP_LENGTH);

            // Get Character's wearing items
            this.headWear = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION +(character_no* DataHandle.EACH_ITEM_LENGTH));

            this.outerArmor = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION + (character_no * DataHandle.EACH_ITEM_LENGTH) +
                (DataHandle.ALL_CHARACTER_NUMBER * DataHandle.EACH_ITEM_LENGTH));

            this.innerArmor = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION + (character_no * DataHandle.EACH_ITEM_LENGTH) +
                (2*DataHandle.ALL_CHARACTER_NUMBER * DataHandle.EACH_ITEM_LENGTH));

            this.weapon = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION + (character_no * DataHandle.EACH_ITEM_LENGTH) +
                (3 * DataHandle.ALL_CHARACTER_NUMBER * DataHandle.EACH_ITEM_LENGTH));

            this.footWear = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION + (character_no * DataHandle.EACH_ITEM_LENGTH) +
                (4 * DataHandle.ALL_CHARACTER_NUMBER * DataHandle.EACH_ITEM_LENGTH));

            this.accessoryWear = BitConverter.ToInt16(tmp,
                DataHandle.WORN_ITEMS_LOCATION + (character_no * DataHandle.EACH_ITEM_LENGTH) +
                (5 * DataHandle.ALL_CHARACTER_NUMBER * DataHandle.EACH_ITEM_LENGTH));
        } 
    }
    internal class DataHandle
    {
        
        internal static Int16 ID_LIXIAOYAO = 0;
        private Character lixiaoyao;
        public Character Lixiaoyao
        {
            get
            {
                return lixiaoyao;
            }
        }

        internal static Int16 ID_ZHAOLINGER = 1;
        private Character zhaolinger;
        public Character Zhaoliner
        {
            get
            {
                return zhaolinger;
            }
        }

        internal static Int16 ID_LINYUERU = 2;
        private Character linyueru;
        public Character Linyueru
        {
            get
            {
                return linyueru;
            }
        }

        internal static Int16 ID_WUHOU = 3;
        private Character wuhou;
        public Character Wuhou
        {
            get
            {
                return wuhou;
            }
        }

        internal static Int16 ID_ANU = 4;
        private Character anu;
        public Character Anu
        {
            get
            {
                return anu;
            }
        }

        internal static Int16 ID_GAILUOJIAO = 5;
        private Character gailuojiao;
        public Character Gailuojiao
        {
            get
            {
                return gailuojiao;
            }
        }

        //
        //*_LOCATION 為某個數值在檔文件中的位置
        //

        // 存檔次數
        internal static int SAVED_TIMES_LOCATION = 0x00;
        private Int16 savedTimes;
        public Int16 SavedTimes{
            get{
                return savedTimes;
            }
            set{
                savedTimes = value;
            }
        }

        // 坐標x
        internal static int X_AXIS_LOCATION = 0x2;
        private Int16 x_Axis;
        public Int16 X_Axis{
            get{
                return x_Axis;
            }
            set{
                x_Axis = value;
            }
        }

        // 坐標y
        internal static int Y_AXIS_LOCATION = 0x4;
        private Int16 y_Axis;
        public Int16 Y_Axis{
            get{
                return y_Axis;
            }
            set{
                y_Axis = value;
            }
        }    

        // 隊伍人數
        internal static int TEAM_MEMBER_NUMBER_LOCATION = 0x6;
        internal static int ONLY_ONE_MEMBER = 0;
        internal static int ONLY_TWO_MEMBER = 1;
        internal static int ONLY_THREE_MEMBER = 2;
        private Int16 teamMemberNumber;
        public Int16 TeamMemberNumber{
            get{
                return teamMemberNumber;
            }
            set{
                teamMemberNumber = value;
            }
        }

        // 場景編號
        internal static int SCENE_NO_LOCATION = 0x8;
        private Int16 sceneNo;
        public Int16 SceneNo{
            get{
                return sceneNo;
            }
            set{
                sceneNo = value;
            }
        }

        // 配色
        internal static int COLOR_LOCATION = 0xa;
        private Int16 color;
        public Int16 Color{
            get{
                return color;
            }
            set{
                color = value;
            }
        }

        // 首位成員之朝向
        internal static int FIRST_MEMBER_DIRECTION_LOCATION = 0xc;
        internal static int FACING_DOWN = 0;
        internal static int FACING_LEFT = 1;
        internal static int FACING_UP = 2;
        internal static int FACING_RIGHT = 3;
        private Int16 firstMemberDirection;
        public Int16 FirstMemberDirection{
            get{
                return firstMemberDirection;
            }
            set{
                firstMemberDirection = value;
            }
        }

        // 背景音樂
        internal static int BACKGROUND_MUSIC_LOCATION = 0xe;
        private Int16 backgroundMusic;
        public Int16 BackgroundMusic{
            get{
                return backgroundMusic;
            }
            set{
                backgroundMusic = value;
            }
        }

        //戰鬥音樂
        internal static int BATTLE_MUSICE_LOCATION = 0x10;
        private Int16 battleMusic;
        public Int16 BattleMusic{
            get{
                return battleMusic;
            }
            set{
                battleMusic = value;
            }
        }

        //戰場編號
        internal static int BATTLE_FIELD_NO_LOCATION = 0x12;
        private Int16 battleFieldNo;
        public Int16 BattleFieldNo{
            get{
                return battleFieldNo;
            }
            set{
                battleFieldNo = value;
            }
        }

        //混沌值
        internal static int CHAOS_VALUE_LOCATION = 0x14;
        private Int16 chaosValue;
        public Int16 ChaosValue{
            get{
                return chaosValue;
            }
            set{
                chaosValue = value;
            }
        }
        //靈葫值
        internal static int LINGHU_VALUE_LOCATION = 0x18;
        private Int16 linghuValue;
        public Int16 LinghuValue{
            get{
                return linghuValue;
            }
            set{
                linghuValue = value;
            }
        }

        //敵人速度
        internal static int ENYMEY_SPEED_LOCATION = 0x1a;
        internal static int ENYMEY_REMAINED_LOOPS_LOCATION = 0x1c;
        private Int16 enymeySpeed;
        public Int16 EnymeySpeed{
            get{
                return enymeySpeed;
            }
            set{
                enymeySpeed = value;
            }
        }
        private Int16 enymeyRemainedLoops;
        public Int16 EnymeyRemainedLoops{
            get{
                return enymeyRemainedLoops;
            }
            set{
               enymeyRemainedLoops  = value;
            }
        }

        //錢
        internal static int MONEY_LOCATION = 0x28;
        private Int32 money;
        public Int32 Money{
            get{
                return money;
            }
            set{
               money  = value;
            }
        }

        //隊伍成員的位置
        internal static int MEMBER_POSITION_LOCATION = 0x2c;
        internal static int EACH_MEMBER_VALUE_LENGTH = 2;
        internal static int EACH_MEMBER_POSITION_LENGTH = 10;
        internal static int POS2_LOCATION = MEMBER_POSITION_LOCATION + EACH_MEMBER_POSITION_LENGTH;
        internal static int POS3_LOCATION = POS2_LOCATION + EACH_MEMBER_POSITION_LENGTH;

        // 角色經驗
        internal static int XP_LOCATION = 0x7c;
        internal static int EACH_XP_LENGTH = 4;
        internal static int EACH_CHARACTER_LENGTH = 8;

        //道具參數設置以及已裝備的道具地址
        internal static int WORN_ITEMS_LOCATION = 0x280;
        internal static int EACH_ITEM_LENGTH = 2;
        internal static int ALL_CHARACTER_NUMBER = 6;

        // 技能

        private string rpgFileName;
        private byte[] RpgDataBytes;

        public DataHandle(string rpg)
        {
            this.rpgFileName = rpg;
            this.RpgDataBytes = File.ReadAllBytes(rpg);

            //Initialization of values
            this.savedTimes = BitConverter.ToInt16(RpgDataBytes, SAVED_TIMES_LOCATION);
            this.x_Axis = BitConverter.ToInt16(RpgDataBytes, X_AXIS_LOCATION);
            this.y_Axis = BitConverter.ToInt16(RpgDataBytes, Y_AXIS_LOCATION);
            this.teamMemberNumber = BitConverter.ToInt16(RpgDataBytes, TEAM_MEMBER_NUMBER_LOCATION);
            this.sceneNo =BitConverter.ToInt16(RpgDataBytes, SCENE_NO_LOCATION);
            this.color = BitConverter.ToInt16(RpgDataBytes, COLOR_LOCATION);
            this.firstMemberDirection = 
                BitConverter.ToInt16(RpgDataBytes, FIRST_MEMBER_DIRECTION_LOCATION);
            this.backgroundMusic = 
                BitConverter.ToInt16(RpgDataBytes, BACKGROUND_MUSIC_LOCATION);
            this.battleMusic = BitConverter.ToInt16(RpgDataBytes, BATTLE_MUSICE_LOCATION);
            this.battleFieldNo = BitConverter.ToInt16(RpgDataBytes, BATTLE_FIELD_NO_LOCATION);
            this.chaosValue = BitConverter.ToInt16(RpgDataBytes, CHAOS_VALUE_LOCATION);
            this.linghuValue = BitConverter.ToInt16(RpgDataBytes, LINGHU_VALUE_LOCATION);
            this.enymeySpeed =BitConverter.ToInt16(RpgDataBytes, ENYMEY_SPEED_LOCATION);
            this.enymeyRemainedLoops =
                BitConverter.ToInt16(RpgDataBytes, ENYMEY_REMAINED_LOOPS_LOCATION);
            this.money =BitConverter.ToInt32(RpgDataBytes, MONEY_LOCATION);


            // Initialize Characters
            this.lixiaoyao = new Character(ID_LIXIAOYAO, this);
            this.zhaolinger = new Character(ID_ZHAOLINGER, this);
            this.linyueru = new Character(ID_LINYUERU, this);
            this.wuhou = new Character(ID_WUHOU, this);
            this.anu = new Character(ID_ANU, this);
            this.gailuojiao = new Character(ID_GAILUOJIAO, this);
        }

        public byte[] getRpgDataBytes()
        {
            return this.RpgDataBytes;
        }

        internal void Save()
        {
            byte[] newLinghuValue = BitConverter.GetBytes(this.linghuValue);
            this.RpgDataBytes[LINGHU_VALUE_LOCATION] = newLinghuValue[0];
            this.RpgDataBytes[LINGHU_VALUE_LOCATION + 1] = newLinghuValue[1];

            byte[] newMoney = BitConverter.GetBytes(this.money);
            this.RpgDataBytes[MONEY_LOCATION] = newMoney[0];
            this.RpgDataBytes[MONEY_LOCATION+1] = newMoney[1];
            this.RpgDataBytes[MONEY_LOCATION + 2] = newMoney[2];
            this.RpgDataBytes[MONEY_LOCATION + 3] = newMoney[3];

            try
            {
                File.WriteAllBytes(this.rpgFileName, this.RpgDataBytes);
                MessageBox.Show("保存成功");
            }
            catch
            {
                MessageBox.Show("未能寫入存檔文件");
            }
        }
    }
    internal class Item
    {
        private Dictionary<Int16, string> itemDictionary;
        public Item()
        {
            this.itemDictionary = new Dictionary<Int16, string>();
        }
    }
}
